﻿
using System;
using System.Collections.Generic;

namespace My.Ioc.Sample
{
    public interface IConcurrency
    {
        int Code { get; }
    }

    public interface IConcurrencyService
    {
        string Name { get; }
        void AddConcurrency(IConcurrency concurrency);
        void RemoveConcurrency(IConcurrency concurrency);
    }

    public class ConcurrencyService : IConcurrencyService
    {
        readonly Dictionary<int, IConcurrency> _concurrencies = new Dictionary<int, IConcurrency>();

        public string Name
        {
            get { return GetType().Name; }
        }

        public void AddConcurrency(IConcurrency concurrency)
        {
            _concurrencies.Add(concurrency.Code, concurrency);
        }

        public void RemoveConcurrency(IConcurrency concurrency)
        {
            _concurrencies.Remove(concurrency.Code);
        }
    }

    public class NewConcurrencyService : IConcurrencyService
    {
        #region IConcurrencyService Members

        public string Name
        {
            get { return GetType().Name; }
        }

        public void AddConcurrency(IConcurrency concurrency)
        {
            throw new NotImplementedException();
        }

        public void RemoveConcurrency(IConcurrency concurrency)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public interface ISimpleConsumer
    {
        IConcurrencyService ConcurrencyService { get; }
    }

    public class SimpleConsumer : ISimpleConsumer
    {
        readonly IConcurrencyService _concurrencyService;

        public SimpleConsumer(IConcurrencyService concurrencyService)
        {
            _concurrencyService = concurrencyService;
        }

        public IConcurrencyService ConcurrencyService
        {
            get { return _concurrencyService; }
        }
    }

    public interface IComplexConsumer : IDisposable
    {
        IConcurrencyService ConcurrencyService { get; }
    }

    public class ComplexConsumer : IComplexConsumer
    {
        readonly string _name;
        readonly IConcurrencyService _concurrencyService;

        public ComplexConsumer(string name, IConcurrencyService concurrencyService)
        {
            _name = name;
            _concurrencyService = concurrencyService;
        }

        public IConcurrencyService ConcurrencyService
        {
            get { return _concurrencyService; }
        }

        public string Name
        {
            get { return _name; }
        }

        public string Address { get; set; }

        public void Print()
        {
            Console.WriteLine(_name + " who lives in " + (Address ?? "Fujian") + " is using the service " + _concurrencyService.Name);
        }

        public void Dispose()
        {
            Console.WriteLine("ComplexConsumer is disposing...");
        }
    }

    class Program
    {
        static IObjectRegistration _concurrencyServiceRegistration;
        static IObjectObserver<ISimpleConsumer> _simpleConsumerObserver;
        static void Main(string[] args)
        {
            // First, we need to create an instance of IObjectContainer.
            IObjectContainer container = new ObjectContainer(true);

            // Then, we register some services
            container.Register<IConcurrencyService, ConcurrencyService>()
                .WhenParentTypeIsAny(typeof(SimpleConsumer), typeof(ComplexConsumer))
                .In(Lifetime.Container())
                .Set("ConcurrencyService")
                .Return(out _concurrencyServiceRegistration);

            container.Register<ISimpleConsumer, SimpleConsumer>();

            var consumerName = Parameter.Positional("Johnny.Liu");
            container.Register<IComplexConsumer, ComplexConsumer>()
                .WithConstructor(consumerName)
                .WithPropertyValue("Address", "Fujian")
                .WithMethod("Print")
                .In(Lifetime.Transient());

            // Finally, don't forget to commit the registrations to the registry.
            container.CommitRegistrations();

            // Now you can ask the container to build instances for you.
            var simpleConsumer1 = container.Resolve<ISimpleConsumer>();

            if (!container.TryGetObserver(out _simpleConsumerObserver))
                throw new Exception();
            _simpleConsumerObserver.Changed += OnObjectBuilderChanged;
            var simpleConsumer2 = container.Resolve(_simpleConsumerObserver);

            using (var scope = container.BeginLifetimeScope())
            {
                var complexConsumer = scope.Resolve<IComplexConsumer>();
            }

            // At last, we will unregister the current concurrency service to let the other concurrency 
            // service implementations to have a chance to replace it.
            container.Unregister(_concurrencyServiceRegistration);
            container.Register(typeof(IConcurrencyService), typeof(NewConcurrencyService));
            // As we said, don't forget to commit the registrations to the registry.
            container.CommitRegistrations();

            using (var scope = container.BeginLifetimeScope())
            {
                var complexConsumer = scope.Resolve<IComplexConsumer>();
            }

            Console.ReadLine();
        }

        static void OnObjectBuilderChanged(ObjectBuilderChangedEventArgs args)
        {
            Console.WriteLine(args.ChangeMode);
        }
    }
}
